package cn.rocky.structures.linked_list;

/**
 * 链表结构.
 * 在链表上添加每个元素的时候,
 * 都需要创建新的 Node 节点,所以这也是一部分耗时的操作。
 */
public class LinkedList<E> implements List<E> {

    transient int size = 0;
    /**
     * 链表首节点
     */
    transient Node<E> first;
    /**
     * 链表尾节点
     */
    transient Node<E> last;

    public LinkedList() {
    }


    /**
     * 链表节点
     */
    private static class Node<E> {

        E item;
        /**
         * 下一个节点
         */
        Node<E> next;
        /**
         * 上一个节点
         */
        Node<E> prev;

        /**
         * 构造方法
         * @param prev      上一个节点
         * @param element   元素
         * @param next      下一个节点
         */
        public Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }

    /**
     * 头插节点
     * 流程: 先把头节点记录下来。之后创建一个新的节点,新的节点构造
     * 函数的头节点入参为null,通过这样的方式构建出一个新的头节点。
     * 原来的头结点,设置 f.prev 连接到 新的头节点, 这样的就可以完成头插的操作了。
     * 如果原来就没有头节点，既头尾节点都是它。
     * @param e 头节点元素
     */
    void linkFirst(E e) {
        final Node<E> f = first;
        final Node<E> newNode =
                new Node<>(null, e, f);
        first = newNode;
        if (f == null) { // 链表未初始化,第一次插入节点
            last = newNode;
        } else {         // 原首节点的上一个节点连接到新插入的节点上
            f.prev = newNode;
        }
        size++;
    }

    /**
     * 尾插法
     * @param e 尾节点元素
     */
    void linkLast(E e) {
        final Node<E> l = last;
        final Node<E> newNode = new Node<>(l, e, null); // 尾插法的下一个节点是空
        last = newNode;
        if (l == null) { // 链表未初始化,第一次插入节点
            first = newNode;
        } else {         // 原尾节点的下一个节点连接到新插入的节点上
            l.next = newNode;
        }
        size++;
    }

    /**
     * 拆链操作, 即给定一个元素,它就可以把当前这个元素的上一个节点和下一个节点进行相连,之后把自己拆除。
     * 该方法常用于 remove 移除元素操作, 因为整个操作过程不需要遍历, 拆除元素后也不需要复制新的空间,
     * 所以实际复杂度为O(1)
     * @param x 节点
     * @return element 元素
     */
    E unlink(Node<E> x) {
        final E element = x.item;
        final Node<E> next = x.next;
        final Node<E> prev = x.prev;

        if (prev == null) { // 如果等于 null,说明该节点上首节点(没有上一个节点)
            first = next;   // 拆链后该节点的下一个节点为首节点
        } else {            // 不等于 null,说明该节点处于中间或尾部
            prev.next = next;  // 该节点的 下一个节点 链接到 该节点的 上一个节点(该节点的前置节点的下一个节点为该节点的后置节点)
            x.prev = null;     // 该节点的 上一个节点为空,解除 与上一个节点的联系
        }

        if (next == null) { // 该节点的下一个节点为空,处于尾节点或者未初始化
            last = prev;    // 直接移除或首位节点一致
        } else {            // 处于链表中间
            next.prev = prev;   // 该节点的 前一个节点 链接为 该节点下一个节点的 前节点(该节点的上一个节点为该节点的下一个节点的前置节点)
            x.next = null;
        }

        x.item = null;
        size--;
        return element;
    }

    @Override
    public boolean add(E e) {
        linkLast(e);
        return true;
    }

    @Override
    public boolean addFirst(E e) {
        linkFirst(e);
        return true;
    }

    @Override
    public boolean addLast(E e) {
        linkLast(e);
        return true;
    }


    @Override
    public boolean remove(Object o) {
        if (o == null) {
            for (Node<E> x = first; x != null; x = x.next) {
                if (x.item == null) {
                    unlink(x);
                    return true;
                }
            }
        } else {
            for (Node<E> x = first; x != null; x = x.next) {
                if (o.equals(x.item)) {
                    unlink(x);
                    return true;
                }
            }
        }
        return false;
    }


    @Override
    public E get(int index) {
        return node(index).item;
    }

    Node<E> node(int index) {
        if (index < (size >> 1)) {
            Node<E> x = first;
            for (int i = 0; i < index; i++)
                x = x.next;
            return x;
        } else {
            Node<E> x = last;
            for (int i = size - 1; i > index; i--)
                x = x.prev;
            return x;
        }
    }

    @Override
    public void printLinkList() {
        if (this.size == 0) {
            System.out.println("链表为空");
        } else {
            Node<E> temp = first;
            System.out.print("目前的列表，头节点：" + first.item + " 尾节点：" + last.item + " 整体：");
            while (temp != null) {
                System.out.print(temp.item + "，");
                temp = temp.next;
            }
            System.out.println();
        }
    }
}
